/* $Id:field.cc $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#include <sstream>
#include <fstream>
#include "../general/util.h"
#include "field.h"
#include "record.h"
#include "../general/general.h"

field::field() {
    nr=0;
    name="";
    type=-1;
    related=0;
    value=map<string,class value>();
    maxValue=0;
    description="";
    abbreviation="";
}

// Field : nr

const int field::getNr() const { return nr; }
void field::setNr(const int v) { nr=v; }
int field::operator<(const field &ck) const { return (this->nr < ck.nr)?1:0; }

// Field : name

const string field::getName() const { return name; }
void field::setName(const string v) { name=v; }

// Field : type

const string fieldType[]={"number","float","enumerate","position","string","relation","parent","children","boolean"};
const int field::getType() const { return type; }
const string field::showType() const {
    if (type<0) return "";
    else return fieldType[type];
}
void field::setType(const int  v) {
    if (v<0 || (unsigned int)v >= sizeof fieldType/sizeof fieldType[0]) type=-1;
    else type=v;
}
void field::setType(const string v) {
    type=-1;
    loopArray(fieldType, tp, string) {
        if (v==*tp) {type=tp_i; break; }
    }
}

// Field : related

class record& field::getRelated() const { if (related==0) throw nullpointer(); return *related; }
void field::setRelated(class record &v) { related=&v; }

// Field : value

class value& field::getValue(const string v) { return value[v]; }
list<class value>& field::listValue() {
    static list<class value> res;
    res.clear();
    loopMap(value,v,class value) {
        res.push_back(*v);
    }
    res.sort();
    return res;
}
void field::setValue(class value &v) {
    if (v.getNr()==0) v.setNr(++maxValue);
    if (v.getName()=="") throw unnamed();
    value[v.getName()]=v;
}
void field::delValue(const string v) { value.erase(v); }
const bool field::isValue(const string v) const { return value.count(v)>0; }

// Field : description

const string field::getDescription() const { return description; }
void field::setDescription(const string v) { description=v; }

// Field : abbreviation

const string field::getAbbreviation() const { return abbreviation; }
void field::setAbbreviation(const string v) { abbreviation=v; }

void field::xml(ofstream &f, int l, int r) {
    f << ncpy(l, "  ") << "<field nr=\"" << getNr() <<
    "\" name=\"" << getName() <<
    "\" type=\"" << showType() <<
    "\" description=\"" << getDescription() <<
    "\" abbreviation=\"" << getAbbreviation() <<
    "\">" << endl;
    if (r<2) try {
        getRelated().xml(f,l+1,r+1);
    } catch (nullpointer n) {}
    if (r==0) {
        loopFieldValue(this, s_value) {
            s_value->xml(f,l+1);
        }
    }
    f << ncpy(l, "  ") << "</field>" << endl;
}
